package entidades;

import util.Util;
import util.MySQL;
import java.util.Date;
import java.util.List;
import java.util.HashMap;
import java.util.LinkedList;
import java.sql.ResultSet;
import java.util.Iterator;
import java.sql.SQLException;
import com.google.gson.Gson;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Map;

/**
 * @author JFM
 */
public class CicloUteco extends Entidad
	{
	private int utecoId;
	private int numero;
	private long capacidad;
	private Date fechaHoraInicio;
	private Date fechaHoraFin;
	private boolean bloqueado;
	private boolean planificado;
        private int utecoIdReal = 0;


	private Uteco uteco;

	static final String NOMBRE_TABLA = "ciclos_uteco";



	// --- Constructores --- //

	public CicloUteco()
		{
		id = 0;
		numero = 0;
		capacidad = 0;
		fechaHoraInicio = null;
		fechaHoraFin = null;
		bloqueado = false;
		planificado = false;
		utecoIdReal = 0;
		utecoId = 0;
		uteco = null;
		}

	public CicloUteco(int id) throws SQLException
		{ super(id); }

	public CicloUteco(String id) throws SQLException
		{ super(id); }

	public CicloUteco(ResultSet result) throws SQLException
		{ super(result); }

	public CicloUteco(ResultSet result, String prefix) throws SQLException
		{ super(result, prefix); }



	// --- Metodos get()/set() --- //

	public int getNumero()
		{ return numero; }
	public void setNumero(int numero)
		{ this.numero = numero; }
	public void setNumero(String numero)
		{ try{ this.numero = Integer.parseInt(numero); }catch(Exception e) {}; }

	public long getCapacidad()
		{ return capacidad; }
	public void setCapacidad(long capacidad)
		{ this.capacidad = capacidad; }
	public void setCapacidad(String capacidad)
		{ try{ this.capacidad = Long.parseLong(capacidad); }catch(Exception e) {}; }

	public Date getFechaHoraFin()
		{ return fechaHoraFin; }
	public void setFechaHoraFin(Date fechaHoraFin)
		{ this.fechaHoraFin = fechaHoraFin; }
	public void setFechaHoraFin(String fechaHoraFin)
		{ this.fechaHoraFin = Util.parseDatetime(fechaHoraFin); }
	public String getFechaHoraFinToString()
		{ return Util.format(fechaHoraFin, "dd/MM/yyyy HH:mm:ss"); }
	public String getFechaFinToString()
		{ return Util.format(fechaHoraFin, "dd/MM/yyyy"); }

	public Date getFechaHoraInicio()
		{ return fechaHoraInicio; }
	public void setFechaHoraInicio(Date fechaHoraInicio)
		{ this.fechaHoraInicio = fechaHoraInicio; }
	public void setFechaHoraInicio(String fechaHoraInicio)
		{ this.fechaHoraInicio = Util.parseDatetime(fechaHoraInicio); }
	public String getFechaHoraInicioToString()
		{ return Util.format(fechaHoraInicio, "dd/MM/yyyy HH:mm:ss"); }
	public String getFechaInicioToString()
		{ return Util.format(fechaHoraInicio, "dd/MM/yyyy"); }

	public boolean isBloqueado()
		{ return bloqueado; }
	public void setBloqueado(boolean bloqueado)
		{ this.bloqueado = bloqueado; }
	public void setBloqueado(String bloqueado)
		{ this.bloqueado = bloqueado != null && ( bloqueado.compareTo("1") == 0 || bloqueado.compareTo("true") == 0); }

	public boolean isPlanificado()
		{ return planificado; }
	public void setPlanificado(boolean planificado)
		{ this.planificado = planificado; }
	public void setPlanificado(String planificado)
		{ this.planificado = planificado != null && ( planificado.compareTo("1") == 0 || planificado.compareTo("true") == 0); }

	public void setUteco(Uteco uteco)
		{ this.uteco = uteco; }
	public Uteco getUteco() throws SQLException
		{
		if(uteco == null || utecoId != uteco.getId())
			{ uteco = new Uteco(utecoId); }
		return uteco;
		}

	public int getUtecoId()
		{ return utecoId; }
	public void setUtecoId(int utecoId)
		{ this.utecoId = utecoId; }
	public void setUtecoId(String utecoId)
		{ try{ this.utecoId = Integer.parseInt(utecoId); }catch(Exception e) {}; }
        public int getUtecoIdReal(){
               return utecoIdReal;
        }
        public void setUtecoIdReal(int utecoIdReal){
            this.utecoIdReal = utecoIdReal;
        }

	@Override
	public String getDescriptor()
		{ return "Inicio: " + Util.format(fechaHoraInicio, "dd/MM/yyyy hh:mm") + " - Uteco: " + utecoId; }

	@Override
	public String toJson()
		{
		HashMap map = new HashMap();
		map.put("id", id);
		map.put("uteco_id", utecoId);
		map.put("numero", numero);
		map.put("capacidad", capacidad);
		map.put("fecha_hora_inicio", Util.format(fechaHoraInicio, "dd/MM/yyyy hh:mm:ss"));
		map.put("fecha_hora_fin", Util.format(fechaHoraFin, "dd/MM/yyyy hh:mm:ss"));
		map.put("bloqueado", bloqueado);
		map.put("planificado", planificado);
		return new Gson().toJson(map);
		}



	// --- Metodos MySQL --- //

	@Override
	public String getNombreTabla()
		{ return NOMBRE_TABLA; }

	@Override
	public void leer(ResultSet result, String prefijo) throws SQLException
		{
		setId(result.getInt(prefijo + "id"));
		setNumero(result.getInt(prefijo + "numero"));
		setCapacidad(result.getLong(prefijo + "capacidad"));
		setFechaHoraInicio(result.getTimestamp(prefijo + "fecha_hora_inicio"));
		setFechaHoraFin(result.getTimestamp(prefijo + "fecha_hora_fin"));
		setUtecoId(result.getInt(prefijo + "uteco_id"));
		setBloqueado(result.getBoolean(prefijo + "bloqueado"));
		setPlanificado(result.getBoolean(prefijo + "planificado"));
		}

	@Override
	public void guardar() throws SQLException
		{
		ResultSet result = MySQL.executeQuery("Call CiclosUteco_Save(" +
				MySQL.formatId(id) + "," +
				MySQL.formatId(utecoId) + "," +
				MySQL.format(numero) + "," +
				MySQL.format(capacidad) + "," +
				MySQL.format(fechaHoraInicio) + "," +
				MySQL.format(fechaHoraFin) + "," +
				MySQL.formatBit(bloqueado) + ", " +
				MySQL.formatBit(planificado) + ")");

		if(result.next())
			{
			if( result.getMetaData().getColumnCount() == 1)
				{
				String msj = result.getString("mensaje");
				throw new SQLException(msj);
				}
			else
				{ leer(result); }
			}

		result.getStatement().close();
		}


	@Override
	public void borrar() throws SQLException
		{ borrar(id+""); }

	public static void borrar(String id) throws SQLException
		{
		String msj = null;
		
		ResultSet result = MySQL.executeQuery("Call CiclosUteco_Delete("+id+")");
		if(result.next())
			{ msj = result.getString("mensaje"); }
		result.getStatement().close();
		
		if(msj != null && msj.compareToIgnoreCase("ok") != 0)
			{ throw new SQLException(msj); }
		}

	/**
	 * Obtiene el ciclo anterior a este ('null' en el caso de que no exista).
	 *
	 * @return Devuelve el ciclo anterior a este.
	 */
	public CicloUteco getAnterior() throws SQLException
		{
		List<CicloUteco> lista = (List) Entidad.buscar(CicloUteco.class, NOMBRE_TABLA, "uteco_id = " + utecoId + " AND numero < " + numero + " ORDER BY numero DESC LIMIT 1");
		if(lista.size() > 0) return lista.get(0);
		return null;
		}

	/**
	 * Verifica si el ciclo tiene ordenes de trabajo asignadas.
	 *
	 * @return Devuelve 'true' si el ciclo tiene ordenes y 'false' en caso contrario.
	 */
	public boolean hasOrdenes() throws SQLException
		{
		boolean res = false;
		ResultSet result = MySQL.executeQuery("SELECT COUNT(*) AS ordenes FROM ordenes_trabajo WHERE ciclo_uteco_id = " + id);
		if(result.next()) { if(result.getInt("ordenes") > 0) res = true; }
		result.getStatement().close();
		return res;
		}

	/**
	 * Obtiene la lista de todos los ciclos Uteco de la base de datos.
	 *
	 * @return Devuelve la lista de ciclos Uteco.
	 */
	public static List<CicloUteco> listar() throws SQLException
		{ return (List) Entidad.listar(CicloUteco.class, NOMBRE_TABLA, "numero ASC, uteco_id ASC"); }

	/**
	 * Obtiene todos los ciclos Uteco cuya fecha de fin es mayor o igual a 'fecha'.
	 *
	 * @param fecha Una fecha.
	 * @return Devuelve la lista de ciclos.
	 */
	public static List<CicloUteco> listar(Date fecha) throws SQLException
		{ return (List) Entidad.buscar(CicloUteco.class, NOMBRE_TABLA, "fecha_hora_fin >= " + MySQL.formatDateMin(fecha) , "numero ASC, uteco_id ASC"); }

	/**
	 * Obtiene todos los ciclos Newlong cuyo numero es igual a 'numero'.
	 *
	 * @param numero El numero de los ciclos.
	 * @return Devuelve la lista de ciclos.
	 */
	public static List<CicloUteco> listar(int numero) throws SQLException
		{ 
                    return (List) Entidad.buscar(CicloUteco.class, NOMBRE_TABLA, "numero = " + numero , "uteco_id ASC"); 
                
                }


	/**
	 * Obtiene todos los ciclos pertenecientes a la Uteco identificada por 'utecoId' cuya fecha de inicio es mayor o igual a 'fecha1' y fecha fin menor o igual a 'fecha2'.
	 *
	 * @param utecoId El id de una Uteco.
	 * @param fecha1 Una fecha.
	 * @param fecha2 Una fecha.
	 * @return Devuelve la lista de ciclos.
	 */
	public static List<CicloUteco> listar(int utecoId, Date fecha1, Date fecha2) throws SQLException
		{ return listar(utecoId, fecha1, fecha2, true); }

	/**
	 * Obtiene todos los ciclos pertenecientes a la Uteco identificada por 'utecoId'.
	 * Si 'estricto' es 'true' selecciona los ciclos cuya fecha de inicio es mayor o igual a 'fecha1' y fecha fin menor o igual a 'fecha2'.
	 * Si 'estricto' es 'false' selecciona los ciclos cuya fecha de inicio es menor o igual a 'fecha2' y fecha fin mayor o igual a 'fecha1'.
	 *
	 * @param utecoId El id de una Uteco.
	 * @param fecha1 Una fecha.
	 * @param fecha2 Una fecha.
	 * @param estricto Un boolean que determina como se comparan las fechas.
	 * @return Devuelve la lista de ciclos.
	 */
	public static List<CicloUteco> listar(int utecoId, Date fecha1, Date fecha2, boolean estricto) throws SQLException
		{ return listar(utecoId, fecha1, fecha2, estricto, null, null); }

	/**
	 * Obtiene todos los ciclos pertenecientes a la Uteco identificada por 'utecoId'.
	 * Si 'estricto' es 'true' selecciona los ciclos cuya fecha de inicio es mayor o igual a 'fecha1' y fecha fin menor o igual a 'fecha2'.
	 * Si 'estricto' es 'false' selecciona los ciclos cuya fecha de inicio es menor o igual a 'fecha2' y fecha fin mayor o igual a 'fecha1'.
	 *
	 * @param utecoId El id de una Uteco.
	 * @param fecha1 Una fecha.
	 * @param fecha2 Una fecha.
	 * @param estricto Un boolean que determina como se comparan las fechas.
	 * @param impresion Un array de tres booleanos.
	 * @param confeccion Un array de tres booleanos.
	 * @return Devuelve la lista de ciclos.
	 */
	public static List<CicloUteco> listar(int utecoId, Date fecha1, Date fecha2, boolean estricto, Boolean[] impresion, Boolean[] confeccion) throws SQLException
		{
		String where = "true";
		if(utecoId > 0) where += " AND uteco_id = " + utecoId;
		
		if(estricto)
			{
			if(fecha1 != null) where += " AND fecha_hora_inicio >= " + MySQL.formatDateMin(fecha1);
			if(fecha2 != null) where += " AND fecha_hora_fin <= " + MySQL.formatDateMax(fecha2);
			}
		else
			{
			if(fecha1 != null) where += " AND fecha_hora_inicio <= " + MySQL.formatDateMin(fecha2);
			if(fecha2 != null) where += " AND fecha_hora_fin >= " + MySQL.formatDateMax(fecha1);
			}
		
		boolean filtroImpresion = impresion != null && impresion.length == 3 && !(impresion[0] && impresion[1]);
		boolean filtroConfeccion = confeccion != null && confeccion.length == 3 && !(confeccion[0] && confeccion[1]);
		if(filtroImpresion || filtroConfeccion)
			{
                        where += " AND EXISTS(SELECT * FROM ordenes_trabajo_util otpc WHERE cu_id = ciclo_uteco_id";
			
			if(filtroImpresion)
				{			
				where += " AND (false";
				if(impresion[0]) where += " OR (estado_id = 1 AND cu_planificado = 0) ";
				if(impresion[1]) where += " OR (cu_planificado = 1 AND estado_id = 1) ";
				if(impresion[2]) where += " OR  estado_id <> 1 ";
				where += ")";
				}
			
			if(filtroConfeccion)
				{			
				where += " AND (false";
				if(confeccion[0]) where += " OR (estado_id <> 3 AND cn_planificado = 0)";
				if(confeccion[1]) where += " OR (cn_planificado = 1 AND estado_id <> 3) ";
				if(confeccion[2]) where += " OR  estado_id = 3 ";
				where += ")";
				}
			 where += ")";
			}
		
		return (List) Entidad.buscar(CicloUteco.class, NOMBRE_TABLA, where, "fecha_hora_inicio ASC");
		}

	/**
	 * Buscar ciclos Uteco.
	 *
	 * @param fecha1 Una fecha.
	 * @param fecha2 Una fecha.
	 * @param bloqueado Un boolean que indica si los ciclos buscados deben estar bloqueados o no.
	 * @param planificado Un boolean que indica si los ciclos buscados deben estar planificados o no.
	 * @return Devuelve la lista de ciclos.
	 */
	public static List<CicloUteco> buscar(Date fecha1, Date fecha2, boolean bloqueado, boolean planificado) throws SQLException
		{
		String where = "true";
		if(fecha1 != null) where += " AND fecha_hora_fin >= " + MySQL.formatDateMin(fecha1);
		if(fecha2 != null) where += " AND fecha_hora_inicio <= " + MySQL.formatDateMax(fecha2);
		if(bloqueado) where += " AND bloqueado = 1";
		if(planificado) where += " AND planificado = 1";
		
		return (List) Entidad.buscar(CicloUteco.class, NOMBRE_TABLA, where, "numero ASC, uteco_id ASC");
		}

	/**
	 * Bloquea o desbloquea todos los ciclos cuyo numero es igual a 'numero'.
	 *
	 * @param numero El numbero de los ciclos que deben ser bloqueados o desbloqueados.
	 * @param bloquear Un boolean que indica si los ciclos deben ser bloqueados o desbloqueados.
	 */
	public static void bloquear(int numero, boolean bloquear) throws SQLException
		{
		List<CicloUteco> ciclos = CicloUteco.listar(numero);
		for(int i=0; i<ciclos.size(); i++)
			{
			CicloUteco c = ciclos.get(i);
			c.setBloqueado(bloquear);
			if(bloquear)
				{
				c.setCapacidad(c.getCapacidadAsignada());
				c.setFechaHoraFin( Uteco.calcularFechaFin(c.getUtecoId(), c.getFechaHoraInicio(), c.getCapacidad()) );
				}
			c.guardar();
			}
		}

	/**
	 * Obtiene la fecha de fin del ciclo, en el caso de que fuese bloqueado y compactado.
	 *
	 * @return La fecha de fin del ciclo si el mismo fuese bloqueado y compactado.
	 */
	public Date getFechaHoraBloqueado() throws SQLException
		{
		long asignada = getCapacidadAsignada();
		if(asignada <= 0)
			return fechaHoraInicio;
		else
			return Uteco.calcularFechaFin(utecoId, fechaHoraInicio, getCapacidadAsignada());
		}
	
	/**
	 * Obtiene los ciclos utecos en donde se puede imprimir una orden de trabajo.
	 * 
	 * La fecha de impresión de dichos ciclos debe cumplir que:
	 * - La diferencia entre la fecha actual y la fecha de impresion sea mayor a los dias dados por 'Tiempos.diasEspera'.
	 * - El tiempo entre que la orden de trabajo es impresa y entre que es confeccionada sea mayor o igual a los dias dados por 'Tiempos.diasDeposito'.
	 *
	 * @param fechaConfeccion La fecha en que sera confeccionada la orden.
	 * @param orden La orden que se quiere imprimir.
	 * @param reprogramacion Un booleano que indica si los ciclos buscados son para reprogramar una orden o para darla de alta (si es un alta, se deben tener en cuenta los dias de espera).
	 * @param planificado Un booleano que indica si se deben incluir ciclos planificados.
	 * @return Devuelve los ciclos en los que la orden puede ser impresa.
	 */
	public static List<CicloUteco> listarDisponibles(Date fechaConfeccion, OrdenTrabajo orden, boolean reprogramacion, boolean planificado) throws SQLException
		{
		LinkedList<CicloUteco> res = new LinkedList();
          	Date fechaDate = new Date();
                long fecha = 0l;
                long diasDeEspera = Tiempos.getDiasEspera()*86400000;
                fecha = fechaDate.getTime() + diasDeEspera;

                int cuerpos = orden.getOrdenVenta().getCantidadColores() + (orden.getOrdenVenta().isBarniz()? 1 : 0);
		Date fechaMin = (reprogramacion)? new Date() : new Date(fecha);
                boolean uvTotal = orden.getOrdenVenta().getLacaUvId() == LacaUv.TOTAL;
		boolean uvSectorizado = orden.getOrdenVenta().getLacaUvId() == LacaUv.SECTORIZADO;

                Integer idNewLong = null;
                if (orden.getCicloNewlong() != null){
                    idNewLong = orden.getCicloNewlong().getNewlong().getId();
                }else{
                    idNewLong = 0;
                }
		ResultSet result = MySQL.executeQuery("CALL CiclosUteco_FechasPosibles(" +
			orden.getMetros() + ", " +
			cuerpos + ", " +
			MySQL.format(fechaMin) + ", " +
			MySQL.format(fechaConfeccion) + ", " +
			MySQL.formatId(idNewLong) + ", " +
			MySQL.formatBit(orden.getOrdenVenta().isInterior()) + ", " +
			MySQL.formatBit(orden.getOrdenVenta().isBarniz()) + ", " +
			MySQL.formatBit(uvSectorizado) + ", " +
			MySQL.formatBit(uvTotal) + ", " +
			MySQL.formatBit(planificado) + ")");
                System.out.println("Fecha confección:" + fechaConfeccion);
                GregorianCalendar calendar = (GregorianCalendar)GregorianCalendar.getInstance();
                calendar.setTime(fechaConfeccion);
                calendar.setFirstDayOfWeek(Calendar.MONDAY);
                System.out.println("Dia de la semana:" + calendar.get(Calendar.DAY_OF_WEEK));
                long dias = 0;
                if (orden.getOrdenVenta().getPais().getId() == Pais.ARGENTINA){
                    if (calendar.get(Calendar.DAY_OF_WEEK) == 1){
                        dias = 86400000*8;
                    }else{
                        dias = 86400000*7;
                    }
                }else{
                     if (calendar.get(Calendar.DAY_OF_WEEK) == 1){
                        dias = 86400000*15;
                    }else{
                        dias = 86400000*14;
                    }
                }
		while(result.next())
			{
                             CicloUteco cu = new CicloUteco(result);
                            //long diasDeposito = (Tiempos.getDiasDeposito(orden.getCicloNewlong().getNewlongId(), cu.getUtecoId()))*86400000;
                            long fechaLongMaxima = fechaConfeccion.getTime() - dias;
                            Date fechaMaxima = new Date(fechaLongMaxima);
                            if (cu.getFechaHoraFin().getTime() >= fechaMaxima.getTime()
                                     && cu.getFechaHoraInicio().getTime() <= fechaMaxima.getTime() 
                                     && (fechaMaxima.getTime() - cu.getFechaHoraInicio().getTime() < 604800000)){
                                        System.out.println("Fecha impresión Argentina:" + cu.getFechaHoraInicio());
                                        res.add( cu );
                                 }
                            
//                            else{
//                                dias = diasDeposito * 86400000 + 86400000*14;
//                                fechaLongMaxima = fechaConfeccion.getTime() - dias;
//                                fechaMaxima = new Date(fechaLongMaxima);
//                                if (cu.getFechaHoraInicio().getTime() <= fechaMaxima.getTime()
//                                     && cu.getFechaHoraFin().getTime() >= fechaMaxima.getTime() ){
//                                res.add( cu );
//                                }
//                            }
                        }
		result.getStatement().close();

		return res;
		}

        public static List<CicloUteco> listarDisponiblesReprogramar(Date fechaConfeccion, OrdenTrabajo orden, boolean reprogramacion, boolean planificado) throws SQLException
		{
		LinkedList<CicloUteco> res = new LinkedList();
          	Date fechaDate = new Date();
                long fecha = 0l;
                long diasDeEspera = Tiempos.getDiasEspera()*86400000;
                fecha = fechaDate.getTime() + diasDeEspera;

                int cuerpos = orden.getOrdenVenta().getCantidadColores() + (orden.getOrdenVenta().isBarniz()? 1 : 0);
		Date fechaMin = (reprogramacion)? new Date() : new Date(fecha);
                boolean uvTotal = orden.getOrdenVenta().getLacaUvId() == LacaUv.TOTAL;
		boolean uvSectorizado = orden.getOrdenVenta().getLacaUvId() == LacaUv.SECTORIZADO;

                Integer idCicloNewLong = null;
                if (orden.getCicloNewlong() != null){
                    idCicloNewLong = orden.getCicloNewlong().getId();
                }else{
                    idCicloNewLong = 0;
                }
		ResultSet result = MySQL.executeQuery("CALL CiclosUteco_FechasPosibles(" +
			orden.getMetros() + ", " +
			cuerpos + ", " +
			MySQL.format(fechaMin) + ", " +
			MySQL.format(fechaConfeccion) + ", " +
			MySQL.formatId(idCicloNewLong) + ", " +
			MySQL.formatBit(orden.getOrdenVenta().isInterior()) + ", " +
			MySQL.formatBit(orden.getOrdenVenta().isBarniz()) + ", " +
			MySQL.formatBit(uvSectorizado) + ", " +
			MySQL.formatBit(uvTotal) + ", " +
			MySQL.formatBit(planificado) + ")");

		while(result.next())
			{
                             CicloUteco cu = new CicloUteco(result);

                                res.add( cu );
                            }
                        
		result.getStatement().close();

		return res;
		}

        public static List<Map> fechasPosibles(OrdenTrabajo orden) throws SQLException{
                LinkedList<Map> res = new LinkedList();
                Calendar fechaFiltro = Calendar.getInstance();

                fechaFiltro.add(Calendar.DATE, Tiempos.getDiasEspera());
                Date fecha = fechaFiltro.getTime();
                System.out.println("Fecha Uteco: " + fecha);
                ResultSet result = MySQL.executeQuery("select cu.* from ciclos_uteco_view cu where cu.metros_disponibles > " + orden.getCantidad() + " and cu.fecha_hora_inicio >" + MySQL.formatDateMax(fecha));
		while(result.next())
			{
                            HashMap map = new HashMap();
                            map.put("cicloUtecoId", result.getInt("id"));
                            map.put("newlongId", result.getInt("uteco_id"));
                            map.put("fechaHoraInicio", result.getDate("fecha_hora_inicio"));
                            map.put("fechaHoraFin", result.getDate("fecha_hora_fin"));
                            map.put("cantidadDisponible", result.getLong("metros_disponibles"));
                            map.put("porcentajeDisponible", (int)(100.0*result.getLong("metros_disponibles")/result.getLong("capacidad")));
                            map.put("capacidad", result.getLong("capacidad"));
                            map.put("cicloNewlongNumero", result.getInt("numero"));
                            res.add(map);
                            }
		result.getStatement().close();
		return res;
        }


	public static List<CicloUteco> listarDisponibles(Date fechaConfeccion, OrdenTrabajo orden) throws SQLException
		{ return listarDisponibles(fechaConfeccion, orden, false, false); }

	/**
	 * Obtiene el ciclo uteco mas proximo en donde se puede imprimir una orden.
	 *
	 * @param fecha La fecha en que sera confeccionada la orden.
	 * @param orden La orden que se imprimira.
	 * @return Devuelve el ciclo mas proximo en el que la orden puede ser impresa.
	 */
	public static CicloUteco getDisponible(Date fecha, OrdenTrabajo orden) throws SQLException
		{
		List<CicloUteco> res = listarDisponibles(fecha, orden);
		return (res != null && res.size() > 0)? res.get(0) : null ;
		}

	/**
	 * Obtiene el id del ciclo numero 'numero' de la uteco identificada por 'utecoId'.
	 *
	 * @param utecoId El id de la Uteco a la que pertenece el ciclo.
	 * @param numero El numero de ciclo.
	 * @return Devuelve el id del ciclo.
	 */
	public static int getCicloId(int utecoId, int numero) throws SQLException
		{
		int res = 0;
		ResultSet result = MySQL.executeQuery("SELECT id FROM "+NOMBRE_TABLA+" WHERE uteco_id = " + utecoId + " AND numero = " + numero + " ORDER BY id DESC LIMIT 1");
		if(result.next()) { res = result.getInt("id"); }
		result.getStatement().close();
		return res;
		}
	
	/**
	 * Calcula la cantidad metros disponibles, para ser impresos, en este ciclo.
	 *
	 * @return Devuelve la capacidad disponible del ciclo.
	 */
	public long getCapacidadDisponible() throws SQLException
		{ return this.getCapacidad() - this.getCapacidadAsignada(); }
	
	public int getPorcentajeDisponible() throws SQLException
		{ return (int)(100.0*getCapacidadDisponible()/getCapacidad()); }

	/**
	 * Calcula la cantidad metros asignados de este ciclo.
	 *
	 * @return Devuelve la capacidad ocupada del ciclo.
	 */
	public long getCapacidadAsignada() throws SQLException
		{
		long res = 0;
		ResultSet result = MySQL.executeQuery("SELECT SUM(metros) AS asignada FROM ordenes_trabajo WHERE ciclo_uteco_id = " + id + " GROUP BY ciclo_uteco_id");
		if(result.next()) {res = result.getLong("asignada");}
		result.getStatement().close();
		return res;
		}

	/**
	 * Obtiene el numero de ciclo que tendra el proximo ciclo de una uteco en particula.
	 *
	 * @param utecoId El id de la uteco en cuestion.
	 * @return Devuelve el proximo numero de ciclo.
	 */
	public static int getProximoNumero(int utecoId) throws SQLException
		{ return getProximoNumero(utecoId, false); }

	public static int getProximoNumero(int utecoId, boolean planificado) throws SQLException
		{
		int res = 1;
		String query = "SELECT MAX(numero) AS numero FROM " + NOMBRE_TABLA + " WHERE uteco_id = " + utecoId;
		if(planificado) query += " AND planificado = 1";
		
		ResultSet result = MySQL.executeQuery(query);
		if(result.next()) { res = result.getInt("numero") + 1;}
		result.getStatement().close();
		return res;
		}
	
	/**
	 * Obtiene la fecha de fin del ultimo ciclo de una uteco en particula.
	 *
	 * @param utecoId El id de la uteco en cuestion.
	 * @return Devuelve la fecha de fin del ultimo ciclo.
	 */
	public static Date getUltimaFecha(int utecoId) throws SQLException
		{
		Date res = null;
		ResultSet result = MySQL.executeQuery("SELECT MAX(fecha_hora_fin) AS fecha_fin FROM " + NOMBRE_TABLA + " WHERE uteco_id = " + utecoId + " ORDER BY fecha_hora_fin DESC");
		if(result.next()) {res = result.getTimestamp("fecha_fin");}
		result.getStatement().close();
		return (res != null)? res : new Date();
		}	

	/**
	 * Obtiene la fecha de inicio de la proxima planificacion.
	 *
	 * @param utecoId El id de la uteco en cuestion.
	 * @return Devuelve la fecha de inicio de la proxima planificacion.
	 */
	public static Date getProximaFechaPlanificacion(int utecoId) throws SQLException
		{
		Date res = null;
		
		ResultSet result = MySQL.executeQuery("SELECT MAX(fecha_hora_fin) AS fecha_fin FROM " + NOMBRE_TABLA + " WHERE uteco_id = " + utecoId + " AND planificado = 1");
		if(result.next()) {res = result.getTimestamp("fecha_fin");}
		result.getStatement().close();
		
		if(res == null)
			{
			result = MySQL.executeQuery("SELECT MAX(fecha_hora_fin) AS fecha_fin FROM " + NOMBRE_TABLA + " WHERE uteco_id = " + utecoId + " AND fecha_hora_inicio < NOW()");
			if(result.next()) {res = result.getTimestamp("fecha_fin");}
			result.getStatement().close();
			}
		
		return (res != null)? res : new Date();
		}

	public Date calcularImpresion(long metros) throws SQLException
		{
		Date fechaImpresion = this.fechaHoraInicio;
		
		long miliseg = (this.fechaHoraInicio !=null && this.fechaHoraFin != null)? (this.fechaHoraFin.getTime() - this.fechaHoraInicio.getTime()) : 0;
		float porcentaje = (capacidad>0)? (metros + this.getCapacidadAsignada())/capacidad : 0;
		if(miliseg > 0 && porcentaje > 0.0)
			{ fechaImpresion.setTime(this.fechaHoraInicio.getTime() + (long)(miliseg * porcentaje)); }
		
		return fechaImpresion;
		}

         public static boolean tieneTodosImpreso(CicloUteco ciclo) throws Exception
		{
		List<OrdenTrabajo> ordenes = OrdenTrabajoView.buscar("ciclo_uteco_id = " + ciclo.getId() + " ORDER BY ciclo_uteco_turno ASC");
		Iterator<OrdenTrabajo> it = ordenes.iterator();
                while (it.hasNext()){
                       OrdenTrabajo ot = (OrdenTrabajo) it.next();
                       if (ot.getEstado().getId() != EstadoTrabajo.IMPRESO){
                           return false;
                       }
                }
		return true;
		}

        public static CicloUteco getUtecoByFechaConfeccion(Date fechaConfeccion, Boolean[] confeccion) throws SQLException
		{
                String where = " ";
                long dias = fechaConfeccion.getTime() - 86400000*6;
                Date fechaNueva = new Date(dias);
                if(fechaConfeccion != null) where += " WHERE cu.fecha_hora_inicio <= " + MySQL.formatDateMin(fechaNueva);

		boolean filtroConfeccion = confeccion != null && confeccion.length == 3 && !(confeccion[0] && confeccion[1]);
		if(filtroConfeccion)
			{
                        where += " AND EXISTS(SELECT * FROM ordenes_trabajo_util otpc WHERE cu_id = ciclo_uteco_id";

			if(filtroConfeccion)
				{
				where += " AND (false";
				if(confeccion[0]) where += " OR (otpc.estado_id <> 3 AND otpc.cn_planificado = 0)";
				if(confeccion[1]) where += " OR (otpc.cn_planificado = 1 AND otpc.estado_id <> 3) ";
				if(confeccion[2]) where += " OR  otpc.estado_id = 3 ";
				where += ")";
				}
			 where += ")";
			}

		return queryByFechaConfeccion(where, "cu.fecha_hora_inicio DESC");
		}

        public static CicloUteco queryByFechaConfeccion(String where, String orderBy) throws SQLException
		{
		LinkedList lista = new LinkedList();
		String query = "SELECT cu.* FROM  ciclos_uteco cu " ;
		if(where != null && where.length() > 0) query += "  " + where;
		if(orderBy != null && orderBy.length() > 0) query += " ORDER BY " + orderBy;

		ResultSet result = MySQL.executeQuery(query);
                System.out.println("Query:" + query);
		CicloUteco entidad = new CicloUteco();
                int i = 0;
                while(result.next() && i == 0)
		{
			entidad.leer(result);
			lista.add(entidad);
                        i++;
			}
		result.getStatement().close();
			
		return entidad;
	}

       public void updateUteco(Integer cicloUtecoId, Integer utecoId) throws SQLException{
           MySQL.executeUpdate("update  ciclos_uteco set uteco_id =  " + utecoId + " WHERE id = " + cicloUtecoId );
       }

       public static CicloUteco listar(int numero, int utecoId) throws SQLException
	{
            List<CicloUteco> lista =  (List) Entidad.buscar(CicloUteco.class, NOMBRE_TABLA, "numero = " + numero + " AND uteco_id = " + utecoId );
            if (!lista.isEmpty()){
                return lista.get(0);
            }else{
                return null;
            }
        }

       public static List<CicloUteco> fechasPosiblesUteco(OrdenTrabajo orden) throws SQLException{
                LinkedList<CicloUteco> res = new LinkedList();
                Calendar fechaFiltro = Calendar.getInstance();

                fechaFiltro.add(Calendar.DATE, Tiempos.getDiasEspera());
                Date fecha = fechaFiltro.getTime();
                ResultSet result = MySQL.executeQuery("select cu.* from ciclos_uteco_view cu where cu.metros_disponibles > " + orden.getCantidad() + " and cu.fecha_hora_inicio >" + MySQL.formatDateMax(fecha));
		while(result.next())
			{
                             CicloUteco cu = new CicloUteco(result);
                                res.add( cu );
                        }
		result.getStatement().close();

		return res;
        }

       public static List<CicloUteco> getCicloUtecoByFechaConfeccion(Date fechaConfeccion, Boolean[] confeccion) throws SQLException
		{
                LinkedList lista = new LinkedList();
                GregorianCalendar calendar = (GregorianCalendar)GregorianCalendar.getInstance();
                calendar.setTime(fechaConfeccion);
                calendar.setFirstDayOfWeek(Calendar.SUNDAY);
                Date primerDia = getPrimerDiaSemana(calendar);
                Date ultimoDia = getUltimoDiaSemana(calendar);
		String query = "select DISTINCT cu.* from ordenes_trabajo ot inner join ciclos_uteco cu on (ot.ciclo_uteco_id = cu.id) inner join ordenes_venta ov on (ov.id = ot.orden_venta_id ) " ;
                query  += " where ot.ciclo_newlong_inicio >= " + MySQL.formatDateMin(primerDia) +  " and ot.ciclo_newlong_inicio <= "+ MySQL.formatDateMax(ultimoDia)  + " AND ov.pais_id = 1";
               

		boolean filtroConfeccion = confeccion != null && confeccion.length == 3 && !(confeccion[0] && confeccion[1]);
		if(filtroConfeccion)
			{
                        query += " AND EXISTS(SELECT * FROM ordenes_trabajo_util otpc WHERE cu_id = ciclo_uteco_id";

			if(filtroConfeccion)
				{
				query += " AND (false";
				if(confeccion[0]) query += " OR (otpc.estado_id <> 3 AND otpc.cn_planificado = 0)";
				if(confeccion[1]) query += " OR (otpc.cn_planificado = 1 AND otpc.estado_id <> 3) ";
				if(confeccion[2]) query += " OR  otpc.estado_id = 3 ";
				query += ")";
				}
			 query += ")";
			}
                query += " union all ";
                query  += "select DISTINCT cu.* from ordenes_trabajo ot inner join ciclos_uteco cu on (ot.ciclo_uteco_id = cu.id) inner join ordenes_venta ov on (ov.id = ot.orden_venta_id ) " ;
                query  += " where ot.ciclo_newlong_inicio >= " + MySQL.formatDateMin(new Date(primerDia.getTime() + 86400000 * 7 )) +  " and ot.ciclo_newlong_inicio <= "+ MySQL.formatDateMax(new Date(ultimoDia.getTime() + 86400000 * 7 ))  + " AND ov.pais_id = 2";
                if(filtroConfeccion)
			{
                        query += " AND EXISTS(SELECT * FROM ordenes_trabajo_util otpc WHERE cu_id = ciclo_uteco_id";

			if(filtroConfeccion)
				{
				query += " AND (false";
				if(confeccion[0]) query += " OR (otpc.estado_id <> 3 AND otpc.cn_planificado = 0)";
				if(confeccion[1]) query += " OR (otpc.cn_planificado = 1 AND otpc.estado_id <> 3) ";
				if(confeccion[2]) query += " OR  otpc.estado_id = 3 ";
				query += ")";
				}
			 query += ")";
			}
		ResultSet result = MySQL.executeQuery(query);
                    System.out.println("Query:" + query );
		
                Map<Integer, CicloUteco> mapaResultados = new HashMap<Integer, CicloUteco>();
                while(result.next() )
		{
			CicloUteco entidad = new CicloUteco();
                        entidad.leer(result);
                        if (!mapaResultados.containsKey(entidad.getNumero())){
                            lista.add(entidad);
                            mapaResultados.put(entidad.getNumero(), entidad);
                         }
                 }
		result.getStatement().close();

          return lista;
        }

        public static Date getPrimerDiaSemana(Calendar calendar){
        if (calendar.get(Calendar.DAY_OF_WEEK) == 2){
            return calendar.getTime();
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 3){
              long fecha = calendar.getTime().getTime() - 86400000;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 4){
              long fecha = calendar.getTime().getTime() - 86400000*2;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 5){
              long fecha = calendar.getTime().getTime() - 86400000*3;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 6){
              long fecha = calendar.getTime().getTime() - 86400000 * 4;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 7){
              long fecha = calendar.getTime().getTime() - 86400000 * 5;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 1 ){
              long fecha = calendar.getTime().getTime() - 86400000 *6;
              return new Date(fecha);
          }

            else{
            return null;
        }
    }

         public static Date getUltimoDiaSemana(Calendar calendar){
        if (calendar.get(Calendar.DAY_OF_WEEK) == 1){
            return calendar.getTime();
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 2){
              long fecha = calendar.getTime().getTime() + 86400000 * 6;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 3){
              long fecha = calendar.getTime().getTime() + 86400000*5;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 4){
              long fecha = calendar.getTime().getTime() + 86400000*4;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 5){
              long fecha = calendar.getTime().getTime() + 86400000 * 3;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 6){
              long fecha = calendar.getTime().getTime() + 86400000 * 2;
              return new Date(fecha);
          }else if (calendar.get(Calendar.DAY_OF_WEEK) == 7 ){
              long fecha = calendar.getTime().getTime() + 86400000 ;
              return new Date(fecha);
          }

            else{
            return null;
        }
    }

    public static boolean tienePendientes(int numero, Date primerDia,Date ultimoDia) throws SQLException{
        boolean tiene = false;
        Date primerDiaChile = new Date(primerDia.getTime() + 7* 86400000);
        Date ultimoDiaChile = new Date(ultimoDia.getTime() + 7* 86400000);
        String query = "select ot.* from ordenes_trabajo ot inner join ciclos_uteco cu on (ot.ciclo_uteco_id = cu.id) " ;
        query  += " where ot.ciclo_newlong_fin >= " + MySQL.formatDateMin(primerDia) +  " and ot.ciclo_newlong_fin <= "+ MySQL.formatDateMax(ultimoDia);
        query += " and cu.numero =  " + numero +  " and ot.estado_id = 1 and cu.planificado = 0 ";
        query += " union ALL ";
        query += " select ot.* from ordenes_trabajo ot inner join ciclos_uteco cu on (ot.ciclo_uteco_id = cu.id)  inner join ciclos_newlong cn on (ot.ciclo_newlong_id = cn.id)";
        query += " inner join newlong n on (n.id = cn.newlong_id) where ot.ciclo_newlong_fin >= " + MySQL.formatDateMin(primerDiaChile) +  " and ot.ciclo_newlong_fin <= "+ MySQL.formatDateMax(ultimoDiaChile);
        query += " and cu.numero =  " + numero +  " and ot.estado_id = 1 and cu.planificado = 0 and n.pais_id = 2";
        ResultSet result = MySQL.executeQuery(query);

          while(result.next() && !tiene  )
		{
                    tiene = true;

                 }
		result.getStatement().close();

       return tiene;

    }

    public static int getCicloUtecoIdDisponibleByFecha(Date dFechaConfeccion,int pais) throws SQLException{
        int semana;
        if(pais == Pais.ARGENTINA){
            semana = 1;
        }else{
            semana = 2;
        }
        
        Date inicioSemanaDeLaConfeccion = Util.obtenerInicioDeSemana(dFechaConfeccion);
        
        boolean primero = false;
        int idCiclo = 0;
//        String query = " select cu.* from ciclos_uteco_view cu where cu.fecha_hora_inicio <= " + fechaConfeccion + " and cu.bloqueado = 0 and cu.planificado = 0 order by cu.fecha_hora_inicio DESC, cu.metros_disponibles DESC";
        //String query = " select cu.* from ciclos_uteco_view cu where cu.fecha_hora_inicio <= " + MySQL.formatDateMax(inicioSemanaDeLaConfeccion) + "and datediff(now(),cu.fecha_hora_fin)<0 and cu.bloqueado = 0 and cu.planificado = 0 order by cu.fecha_hora_inicio DESC, cu.metros_disponibles DESC";
        String query = "select id " +
                        "from ciclos_uteco_view cu "+
                        "where cu.bloqueado = 0 and cu.planificado = 0  "+
                        "and CEILING(DATEDIFF("+ MySQL.formatDateMax(inicioSemanaDeLaConfeccion) +",cu.fecha_hora_inicio) / 7) = "+ semana +" "+
                        "order by cu.fecha_hora_inicio DESC, cu.metros_disponibles DESC ";
        ResultSet result = MySQL.executeQuery(query);
        while (result.next() && !primero){
               primero = true;
               idCiclo = result.getInt("id");
             }

        return idCiclo;

       }

}
